package pubsub;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import reactor.util.annotation.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public abstract class AbstractSubscriber implements Subscriber {
    protected static final Lock objsLock = new ReentrantLock();
    protected static final List<AbstractSubscriber> objs = new ArrayList<>();
    protected final Map<Channel, GrpPrioPair> channels = new HashMap<>();
    protected static Log logger;

    public Log getLogger() {
        return logger;
    }

    @Override
    public String toString() {
        return getClass().getName();
    }

    public String getName() {
        return toString();
    }

    public static List<AbstractSubscriber> getObjs() {
        return objs;
    }

    public AbstractSubscriber() {
        objsLock.lock();
        objs.add(this);
        objsLock.unlock();
        logger = LogFactory.getLog(this.getClass());
    }

    @Nullable
    public GrpPrioPair getGrpPrioPair(Channel channel) {
        return channels.get(channel);
    }

    @Nullable
    public GrpPrioPair getGrpPrioPair(String channel) {
        return getGrpPrioPair(Channel.get(channel));
    }

    public void unsubscribe(Channel channel) {
        channels.remove(channel);
        channel.removeSubscriber(this);
    }

    public void unsubscribe(String channel) {
        unsubscribe(Channel.get(channel));
    }

    private void _subscribe(Channel channel, GrpPrioPair pair) {
        channels.put(channel, pair);
    }

    public void subscribe(Channel channel, int groupId, int priorityId) {
        _subscribe(channel, channel.addSubscriber(this, groupId, priorityId));
    }

    public void subscribe(String channel, int groupId, int priorityId) {
        subscribe(Channel.get(channel), groupId, priorityId);
    }

    public void subscribe(Channel channel, int groupId) {
        _subscribe(channel, channel.addSubscriber(this, groupId));
    }

    public void subscribe(String channel, int groupId) {
        subscribe(Channel.get(channel), groupId);
    }

    public void subscribe(Channel channel) {
        _subscribe(channel, channel.addSubscriber(this));
    }

    public void subscribe(String channel) {
        subscribe(Channel.get(channel));
    }
}